#ifndef AVALON_MYSQLSERVICELOCATORDATASTORE_HPP
#define AVALON_MYSQLSERVICELOCATORDATASTORE_HPP
#include <boost/scoped_ptr.hpp>
#include "Avalon/Network/Network.hpp"
#include "Avalon/ServiceLocator/ServiceLocatorDataStore.hpp"

namespace mysqlpp {
  class Connection;
}

namespace Avalon {
namespace ServiceLocator {

  /*! \class MySqlServiceLocatorDataStore
   *  \brief Implements the ServiceLocatorDataStore using MySQL.
   *  \author Kamal Mansouri <kranar@hotmail.com>
   */
  class MySqlServiceLocatorDataStore : public ServiceLocatorDataStore {
    public:

      //! Constructs a MySqlServiceLocatorDataStore.
      /*!
        \param address The IP address of the MySQL database to connect to.
        \param schema The name of the schema.
        \param username The username to connect as.
        \param password The password associated with the <i>username</i>.
      */
      MySqlServiceLocatorDataStore(const Network::IpAddress& address,
        const std::string& schema, const std::string& username,
        const std::string& password);

      virtual ~MySqlServiceLocatorDataStore();

      virtual int LoadAccountCount();

      virtual DirectoryEntry::Tag LoadTag(unsigned int id);

      virtual DirectoryEntry::Tag LoadParentTag(unsigned int id);

      virtual DirectoryEntry::Tag LoadAccountTag(const std::string& name);

      virtual unsigned int CreateDirectory(const std::string& name,
        const DirectoryEntry::Tag& directory);

      virtual void DeleteDirectory(unsigned int id);

      virtual void MoveEntry(unsigned int id, unsigned int directory);

      virtual std::vector<DirectoryEntry::Tag> LoadDirectoryEntries(
        unsigned int id);

      virtual unsigned int CreateAccount(const std::string& name,
        const DirectoryEntry::Tag& directory);

      virtual void DeleteAccount(unsigned int id);

      virtual std::string LoadPassword(unsigned int account);

      virtual void SetPassword(unsigned int account,
        const std::string& password);

      virtual std::map<unsigned int, Directory::Permission>
        LoadPermissions(unsigned int id);

      virtual Directory::Permission LoadAccountPermissions(unsigned int account,
        unsigned int directory);

      virtual void SetPermissions(unsigned int account, unsigned int directory,
        Directory::Permission permissions);

      virtual std::vector<std::string> GetUnavailableNames();

      virtual bool IsNameAvailable(const std::string& name);

      virtual void AddUnavailableName(const std::string& name);

      virtual void RemoveUnavailableName(const std::string& name);

      virtual void Connect();

      virtual bool IsConnected();

      virtual void Close();

      virtual boost::signals2::connection ConnectClosedSignal(
        const ClosedSignal::slot_type& slot);

      virtual boost::signals2::connection ConnectClosedSignal(
        const ClosedSignal::slot_type& slot, bool* isConnected);

    private:
      Network::IpAddress m_address;
      std::string m_schema;
      std::string m_username;
      std::string m_password;
      boost::scoped_ptr<mysqlpp::Connection> m_databaseConnection;
      bool m_isConnected;
      unsigned int m_nextEntryId;
      ClosedSignal m_closedSignal;

      unsigned int LoadNextEntryId();
  };
}
}

#endif // AVALON_MYSQLSERVICELOCATORDATASTORE_HPP
